#include "gPath.h"

bool gPath::addGTypeGo(gTypeGo &go, gTypeGo *prev){

	if(prev == NULL){
		moveTo(go[0], go[1]);
		return true;
	}
	return false;
}

void gPath::addGContainer(gObjectContainer &container){

	gObjectContainer::iterator iter = container.begin();
	
	for(; iter != container.end(); iter++)
		addGObject(**iter);

}

void gPath::addGObject(gObject &object){

	gObject::iterator iter = object.begin();
	gTypeGo *buff = NULL;
	
	for(; iter != object.end(); iter++){
		addGTypeGo(*dynamic_cast<gTypeGo *>(*iter), buff);
		buff = dynamic_cast<gTypeGo *>(*iter);
	}

}

bool gPathMoves::addGTypeGo(gTypeGo &go, gTypeGo *prev){

	if(!gPath::addGTypeGo(go, prev) && go.getTypeValue() == TYPE_LINEAR_MOVE){
		if(prev->getTypeValue() != TYPE_LINEAR_MOVE)
			moveTo((*prev)[0], (*prev)[1]);
		lineTo(go[0], go[1]);
		return true;
	}
	return false;

}

float gPathCuts::vectorAngle(float a0, float a1, float b0, float b1) const{

	return atan2(b1, b0) - atan2(a1, a0);

}

float gPathCuts::degrees(float radians) const{

	float angle = 180 / M_PI * radians;
	
	if(angle < 0)
		return angle + 360;
	return angle;

}

void gPathCuts::addGTypeGoCircle(gTypeGoCircle &go, gTypeGo &prev){

	QRectF rect;
	float s[2];
	float r, startAngle, endAngle;
	
	s[0] = prev[0] + go[3];
	s[1] = prev[1] + go[4];
	r = sqrt((go[0] - s[0]) * (go[0] - s[0]) + (go[1] - s[1]) * (go[1] - s[1]));
	rect.setCoords(s[0] - r, s[1] + r, s[0] + r, s[1] - r);
	startAngle = degrees(atan2(prev[1] - s[1], prev[0] - s[0]));	
	endAngle = degrees(atan2(go[1] - s[1], go[0] - s[0]));	
	if(go.getTypeValue() == TYPE_ARC_COUNTER){
		endAngle = endAngle - startAngle;
		if(endAngle < 0)
			endAngle += 360;
	}
	if(go.getTypeValue() == TYPE_ARC_CLOCK){
		endAngle = endAngle - startAngle;
		if(endAngle > 0)
			endAngle -= 360;
	}
	arcTo(rect, startAngle, endAngle);

}

bool gPathBuff::addGTypeGo(gTypeGo &go, gTypeGo *prev){

	gPathCuts::addGTypeGo(go, prev);
	if(go.getTypeValue() == TYPE_LINEAR_MOVE){
		lineTo(go[0], go[1]);
		return true;
	}
	return false;

}

bool gPathCuts::addGTypeGo(gTypeGo &go, gTypeGo *prev){

	if(!gPath::addGTypeGo(go, prev) && prev->getTypeValue() == TYPE_LINEAR_MOVE)
		moveTo((*prev)[0], (*prev)[1]);
	switch(go.getTypeValue()){
		case TYPE_LINEAR_CUT:
			lineTo(go[0], go[1]);
			return true;
		case TYPE_ARC_CLOCK:
			addGTypeGoCircle(dynamic_cast<gTypeGoCircle &>(go), *prev);
			return true;
		case TYPE_ARC_COUNTER:
			addGTypeGoCircle(dynamic_cast<gTypeGoCircle &>(go), *prev);
			return true;
	}
	return false;

}

gPathPoints::gPathPoints(QMatrix *m): matrix(m){}

bool gPathPoints::addGTypeGo(gTypeGo &go, gTypeGo *prev){
	
	QPointF point;

	point.setX(go[0]);
	point.setY(go[1]);
	addGPoint(point);
	return true;
	
}

void gPathPoints::addGPoint(const QPointF &point){

	QRectF rect;
	float size;
	
	size = POINT_SIZE / matrix->m11();
	rect.setCoords(point.x() - size, point.y() + size, point.x() + size, point.y() - size);
	addRect(rect);

}

void gPathPoints::addGBuffPoint(const QPointF &point){

    float size = POINT_SIZE / matrix->m11();

    moveTo(point.x() - size, point.y() + size);
    lineTo(point.x() + size, point.y() - size);
    moveTo(point.x() + size, point.y() + size);
    lineTo(point.x() - size, point.y() - size);

}

void gPathPoints::addGObject(gObject &object){

	QPointF point;
	gObject::iterator iter = object.begin();
	gTypeGo *go;
	
	for(; iter != object.end(); iter++){
		go = dynamic_cast<gTypeGo *>(*iter);
		point.setX((*go)[0]);
		point.setY((*go)[1]);
		addGPoint(point);
	}

}

void gPathLine::addLineGo(gObject &object, int i){
	
    gTypeGo *prev, *go;
	
    go = dynamic_cast<gTypeGo *>(object.at(i));
    if(i < 1)
		prev = NULL;
	else{
        prev = dynamic_cast<gTypeGo *>(object.at(i - 1));
		moveTo((*prev)[0], (*prev)[1]);
	}
    addGTypeGo(*go, prev);
	
}

void gPathLine::addAxis(gObject &object, gTypeGo &go){

	int i = object.getIndexByObject(static_cast<gType *>(&go)) - 1;
	gTypeGo &prev = dynamic_cast<gTypeGo &>(*object.at(i));
	
	moveTo(go[0], go[1]);
	lineTo(prev[0] + go[3], prev[1] + go[4]);
	lineTo(prev[0], prev[1]);

}
